﻿using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace IAD2
{
    class NeuronGas : Algorithm
    {
        protected static StreamWriter sw;
        protected double neighbourhood_range_max, neighbourhood_range_min;
        protected bool gaus, sleep;
        protected int sleep_time;
        protected int epoc;
        public NeuronGas(Network net, List<Neuron> pattern, double n, double neighbourhood_range_max = 0.5, double neighbourhood_range_min = 0.01, int sleep = 0)
            : base(net, pattern, n)
        {
            this.neighbourhood_range_max = neighbourhood_range_max;
            this.neighbourhood_range_min = neighbourhood_range_min;
            if (sleep > 0)
                this.sleep = true;
            else
                this.sleep = false;
            this.sleep_time = sleep;
            /*
            if(sw == null)
                sw = File.CreateText("Gas.LOG");
             * */
        }
        public override void action(int epocNumber, double eps = 0.0001)
        {

            Random random = new Random();
            do
            {

                int pattternNumber = random.Next(pattern.Count);
                net.sortNeuronsByDistance(pattern[pattternNumber]);
                if (this.sleep)
                    net.points.First().goSleep(sleep_time);


                for (int k = 0; k < net.points.Count; k++)
                {

                    net.points[k].moveTo(pattern[pattternNumber], this.Func(epoc, k, epocNumber));
                }
                if (epoc % 10 == 0)
                    this.createChart("Gas-epoc" + epoc + ".png");
                epoc++;
            } while (net.diffLast() > eps && epoc < epocNumber);

        }

        public double Func(int epoc, int k, int epocNumber)
        {
           
            return this.N(epoc, epocNumber) * Math.Exp(-k / Neigbourhood(epoc, epocNumber));
        }

        public double Neigbourhood(int epoc, int epocNumber)
        {
            return this.neighbourhood_range_max * Math.Pow((this.neighbourhood_range_min / this.neighbourhood_range_max), (double)epoc / (double)epocNumber);
        }

        public double N(int epoc, int epocNumber)
        {
            return this.n * Math.Pow((0.001 / this.n), (double)epoc / (double)epocNumber);
        }

        public string getResult()
        {
            return epoc + " & " + net.countZombie() + " & " + this.n + " & " + this.neighbourhood_range_min + " & " + this.neighbourhood_range_max + "  & " + this.sleep_time + " \\\\ \\hline";

        }
    }
}
